﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using OpenTK;
using OpenTK.Graphics.OpenGL;
using System.Drawing;
using System.Drawing.Imaging;

using OOGL;

namespace TestGraphics
{
    public class DrawBox
    {
        public static Size screenSize = new Size(1024, 768);

        public static void Main(string[] args)
        {
            Console.WriteLine("Linux: {0}", Configuration.RunningOnLinux);
            Console.WriteLine("MacOS: {0}", Configuration.RunningOnMacOS);
            Console.WriteLine("Mono: {0}", Configuration.RunningOnMono);
            Console.WriteLine("Unix: {0}", Configuration.RunningOnUnix);
            Console.WriteLine("Windows: {0}", Configuration.RunningOnWindows);
            Console.WriteLine("X11: {0}", Configuration.RunningOnX11);

            //Bitmap temp = new Bitmap("terrain.png");
            //for (int x = 0; x < 256; x += 16)
            //    for (int y = 0; y < 256; y += 16)
            //    {
            //        Bitmap s = new Bitmap(16, 16);
            //        for (int sx = 0; sx < 16; sx++)
            //            for (int sy = 0; sy < 16; sy++)
            //                s.SetPixel(sx, sy, temp.GetPixel(x + sx, y + sy));

            //        s.Save(string.Format("images/{0}_{1}.png", x, y));
            //    }

            int AA = 16;
            GameWindow gw = new GameWindow(screenSize.Width, screenSize.Height, new OpenTK.Graphics.GraphicsMode(new OpenTK.Graphics.ColorFormat(32), 32, 4, AA, new OpenTK.Graphics.ColorFormat(32)));

            FrameBuffer fbo = new FrameBuffer(screenSize.Width, screenSize.Height);
            fbo.Use();

            // Make camera & background
            GL.ClearColor(1f, 1f, 1f, 0.0f);
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
            GL.Enable(EnableCap.DepthTest);

            Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, screenSize.Width / (float)screenSize.Height, 0.1f, 64.0f);
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadMatrix(ref projection);

            Matrix4 modelview = Matrix4.LookAt(new Vector3(-10f, 10f, -10f), Vector3.Zero, Vector3.UnitY);
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadMatrix(ref modelview);

            describeError(GL.GetError());

            // Load textures
            TextureCache.Instance.LoadTexture("images/0_16.png", "cobblestone");
            TextureCache.Instance.LoadTexture("images/0_48.png", "sponge");
            TextureCache.Instance.LoadTexture("images/32_48.png", "diamondore");

            // Draw
            // Axes
            // X
            GL.Begin(BeginMode.Lines);
            GL.Color3(Color.Red);
            foreach (Vector3 v in new Vector3[] { Vector3.Zero, Vector3.UnitX * 10 })
                GL.Vertex3(v);
            GL.End();

            describeError(GL.GetError());

            // Y
            GL.Begin(BeginMode.Lines);
            GL.Color3(Color.Blue);
            foreach (Vector3 v in new Vector3[] { Vector3.Zero, Vector3.UnitY * 10 })
                GL.Vertex3(v);
            GL.End();

            describeError(GL.GetError());

            // Z
            GL.Begin(BeginMode.Lines);
            GL.Color3(Color.Green);
            foreach (Vector3 v in new Vector3[] { Vector3.Zero, Vector3.UnitZ * 10 })
                GL.Vertex3(v);
            GL.End();

            describeError(GL.GetError());

            // End render
            //GL.Ext.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0);

            // Draw
            // Cubes
            //drawCube(new Vector3(-2, 2, 0), Color.Blue);
            drawCube(new Vector3(-2, -2, 0), Color.Red);
            //drawCube(new Vector3(0, 0, 0), Color.Yellow);
            drawCube(new Vector3(2, 2, 0), Color.Green);
            drawCube(new Vector3(2, -2, 0), Color.Cyan);
            drawCube(new Vector3(5, 5, 0), Color.LightGreen);

            Cube c1 = new Cube(5 * Vector3.UnitX); 
            c1.Draw("sponge");

            Cube c2 = new Cube(5 * Vector3.UnitY); 
            c2.Draw("cobblestone");

            Cube c3 = new Cube(5 * Vector3.UnitZ); 
            c3.Draw("diamondore");

            Cube c4 = new Cube(1 * Vector3.UnitX);
            c4.Draw("sponge");

            Cube c5 = new Cube(3 * Vector3.UnitY);
            c5.Draw("diamondore");


            describeError(GL.GetError());

            Bitmap b = GrabScreenshot();
            b.Save("out.bmp");

            Console.WriteLine("Done");
            Console.ReadLine();
        }

        static void describeError(ErrorCode code)
        {
            string s = "[" + (int)code + " " + code.ToString() + "]";

            Console.WriteLine(s);
        }

        static void drawCube(Vector3 offset, Color color)
        {
            var cubeIndices = new int[] 
                        { 
                                // front face
                                0, 1, 2, 2, 3, 0, 
                                // top face
                                3, 2, 6, 6, 7, 3, 
                                // back face
                                7, 6, 5, 5, 4, 7, 
                                // left face
                                4, 0, 3, 3, 7, 4, 
                                // bottom face
                                0, 1, 5, 5, 4, 0,
                                // right face
                                1, 5, 6, 6, 2, 1
                        };

            var cubeVertices = new Vector3[] 
                        {
                                offset + new Vector3 (-0.5f, -0.5f, 0.5f),
                                offset + new Vector3 (0.5f, -0.5f, 0.5f),
                                offset + new Vector3 (0.5f, 0.5f, 0.5f), 
                                offset + new Vector3 (-0.5f, 0.5f, 0.5f), 
                                offset + new Vector3 (-0.5f, -0.5f, -0.5f), 
                                offset + new Vector3 (0.5f, -0.5f, -0.5f), 
                                offset + new Vector3 (0.5f, 0.5f, -0.5f), 
                                offset + new Vector3 (-0.5f, 0.5f, -0.5f) 
                        };

            GL.Begin(BeginMode.Triangles);
            GL.Color3(color);
            foreach (int index in cubeIndices)
                GL.Vertex3(cubeVertices[index]);
            GL.End();
        }


        public static Bitmap GrabScreenshot()
        {
            if (OpenTK.Graphics.GraphicsContext.CurrentContext == null)
                throw new OpenTK.Graphics.GraphicsContextMissingException();

            Bitmap bmp = new Bitmap(screenSize.Width, screenSize.Height);
            BitmapData data = bmp.LockBits(new Rectangle(0, 0, screenSize.Width, screenSize.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            GL.ReadPixels(0, 0, screenSize.Width, screenSize.Height, OpenTK.Graphics.OpenGL.PixelFormat.Bgr, PixelType.UnsignedByte, data.Scan0);
            bmp.UnlockBits(data);

            bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
            return bmp;
        }
    }
}
